﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;

namespace MetaProperties.Collections
{
    /// <summary>
    /// A read only observable keyed collection.
    /// </summary>
    /// <typeparam name="KeyT">The type of the key for the elements in the list.</typeparam>
    /// <typeparam name="ItemT">The type of the elements in the list.</typeparam>
    public partial class ReadOnlyObservableKeyedCollection<KeyT, ItemT> : ReadOnlyObservableCollection<ItemT>, IObservableKeyedCollection<KeyT, ItemT>
    {
        /// <summary>
        /// The writable parent collection.
        /// </summary>
        private readonly IObservableKeyedCollection<KeyT, ItemT> parent;

        /// <summary>
        /// Initializes a new instance of the <see cref="ReadOnlyObservableKeyedCollection&lt;KeyT, ItemT&gt;"/> class.
        /// </summary>
        /// <param name="parent">The writable parent collection.</param>
        public ReadOnlyObservableKeyedCollection(IObservableKeyedCollection<KeyT, ItemT> parent)
            : base(parent)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            this.parent = parent;
        }

        /// <summary>
        /// Gets or sets the item with the specified key.
        /// </summary>
        /// <param name="key">The key of the item.</param>
        /// <value>The item with the specified key.</value>
        public ItemT this[KeyT key]
        {
            get
            {
                return this.parent[key];
            }

            set
            {
                throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// Gets or sets the item at the specified index.
        /// </summary>
        /// <param name="index">The index of the item.</param>
        public ItemT this[int index]
        {
            get
            {
                return this.parent[index];
            }

            set
            {
                throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// Removes the <see cref="T:System.Collections.Generic.IList`1"/> item at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the item to remove.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        ///  <paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </exception>
        /// <exception cref="T:System.NotSupportedException">
        /// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
        /// </exception>
        public void RemoveAt(int index)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// Inserts an item to the <see cref="T:System.Collections.Generic.IList`1"/> at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
        /// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        ///  <paramref name="index"/> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </exception>
        /// <exception cref="T:System.NotSupportedException">
        /// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
        /// </exception>
        public void Insert(int index, ItemT item)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// Adds the specified items to the collection.
        /// </summary>
        /// <param name="items">The items to add.</param>
        public void AddRange(IEnumerable<ItemT> items)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// Determines whether the collection contains an item with the specified key.
        /// </summary>
        /// <param name="key">The key of the item.</param>
        /// <returns>
        ///  <c>true</c> if an item with the specified key exists; otherwise, <c>false</c>.
        /// </returns>
        public bool Contains(KeyT key)
        {
            return this.parent.Contains(key);
        }

        /// <summary>
        /// Gets the index of the item with the speficied key.
        /// </summary>
        /// <param name="key">The key of the item.</param>
        /// <returns>
        /// The index of the item with the speficied key.
        /// </returns>
        public int IndexOf(KeyT key)
        {
            return this.parent.IndexOf(key);
        }

        /// <summary>
        /// Tries to the get the item with the speficied key.
        /// </summary>
        /// <param name="key">The key of the item.</param>
        /// <param name="value">The value.</param>
        /// <returns>
        /// True if the item exists, false otherwise.
        /// </returns>
        public bool TryGetValue(KeyT key, out ItemT value)
        {
            return this.parent.TryGetValue(key, out value);
        }

        /// <summary>
        /// Removes the item with the specified key.
        /// </summary>
        /// <param name="key">The key of the item.</param>
        /// <returns>
        /// True if an item was removed, false otherwise.
        /// </returns>
        public bool Remove(KeyT key)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// Returns the items as an array.
        /// </summary>
        /// <returns>The items as an array.</returns>
        public ItemT[] ToArray()
        {
            return this.parent.ToArray();
        }

        /// <summary>
        /// Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1"/>.
        /// </summary>
        /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1"/>.</param>
        /// <returns>
        /// The index of <paramref name="item"/> if found in the list; otherwise, -1.
        /// </returns>
        public int IndexOf(ItemT item)
        {
            return this.parent.IndexOf(item);
        }
    }
}
